// ==++==
//
//   
//    Copyright (c) 2006 Microsoft Corporation.  All rights reserved.
//   
//    The use and distribution terms for this software are contained in the file
//    named license.txt, which can be found in the root of this distribution.
//    By using this software in any fashion, you are agreeing to be bound by the
//    terms of this license.
//   
//    You must not remove this notice, or any other, from this software.
//   
//
// ==--==

//
// Tests rountriping of various encodings for XML documents with focus on endianess problems.
//

using System;
using System.IO;
using System.Xml;
using System.Text;

class MainApp 
{
    static byte[][] cases = {
        new byte[] { // unicode - little endian
                        0xFF, 0xFE, 0x3C, 0x00, 0x3F, 0x00, 0x78, 0x00, 0x6D, 0x00, 0x6C, 0x00,
                        0x20, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00,
                        0x6F, 0x00, 0x6E, 0x00, 0x3D, 0x00, 0x22, 0x00, 0x31, 0x00, 0x2E, 0x00,
                        0x30, 0x00, 0x22, 0x00, 0x20, 0x00, 0x65, 0x00, 0x6E, 0x00, 0x63, 0x00,
                        0x6F, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x67, 0x00, 0x3D, 0x00,
                        0x22, 0x00, 0x75, 0x00, 0x74, 0x00, 0x66, 0x00, 0x2D, 0x00, 0x31, 0x00,
                        0x36, 0x00, 0x22, 0x00, 0x3F, 0x00, 0x3E, 0x00, 0x0A, 0x00, 0x3C, 0x00, 
                        0x61, 0x01, 0x3E, 0x00, 0x0A, 0x00, 0x3C, 0x00, 0x2F, 0x00, 0x61, 0x01, 
                        0x3E, 0x00
                    },
        new byte[] { // unicode - little endian, NO BOM
                                    0x3C, 0x00, 0x3F, 0x00, 0x78, 0x00, 0x6D, 0x00, 0x6C, 0x00,
                        0x20, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00,
                        0x6F, 0x00, 0x6E, 0x00, 0x3D, 0x00, 0x22, 0x00, 0x31, 0x00, 0x2E, 0x00,
                        0x30, 0x00, 0x22, 0x00, 0x20, 0x00, 0x65, 0x00, 0x6E, 0x00, 0x63, 0x00,
                        0x6F, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x67, 0x00, 0x3D, 0x00,
                        0x22, 0x00, 0x75, 0x00, 0x74, 0x00, 0x66, 0x00, 0x2D, 0x00, 0x31, 0x00,
                        0x36, 0x00, 0x22, 0x00, 0x3F, 0x00, 0x3E, 0x00, 0x0A, 0x00, 0x3C, 0x00, 
                        0x61, 0x01, 0x3E, 0x00, 0x0A, 0x00, 0x3C, 0x00, 0x2F, 0x00, 0x61, 0x01, 
                        0x3E, 0x00
                    },
        new byte[] { // unicode - big endian
                        0xFE, 0xFF, 0x00, 0x3C, 0x00, 0x3F, 0x00, 0x78, 0x00, 0x6D, 0x00, 0x6C,
                        0x00, 0x20, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69,
                        0x00, 0x6F, 0x00, 0x6E, 0x00, 0x3D, 0x00, 0x22, 0x00, 0x31, 0x00, 0x2E,
                        0x00, 0x30, 0x00, 0x22, 0x00, 0x20, 0x00, 0x65, 0x00, 0x6E, 0x00, 0x63,
                        0x00, 0x6F, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x67, 0x00, 0x3D,
                        0x00, 0x22, 0x00, 0x75, 0x00, 0x6E, 0x00, 0x69, 0x00, 0x63, 0x00, 0x6F,
                        0x00, 0x64, 0x00, 0x65, 0x00, 0x46, 0x00, 0x46, 0x00, 0x46, 0x00, 0x45,
                        0x00, 0x22, 0x00, 0x3F, 0x00, 0x3E, 0x00, 0x0A, 0x00, 0x3C, 0x01, 0x61, 
                        0x00, 0x3E, 0x00, 0x0A, 0x00, 0x3C, 0x00, 0x2F, 0x01, 0x61, 0x00, 0x3E,
    },
        new byte[] { // unicode - big endian, NO BOM
                                    0x00, 0x3C, 0x00, 0x3F, 0x00, 0x78, 0x00, 0x6D, 0x00, 0x6C,
                        0x00, 0x20, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69,
                        0x00, 0x6F, 0x00, 0x6E, 0x00, 0x3D, 0x00, 0x22, 0x00, 0x31, 0x00, 0x2E,
                        0x00, 0x30, 0x00, 0x22, 0x00, 0x20, 0x00, 0x65, 0x00, 0x6E, 0x00, 0x63,
                        0x00, 0x6F, 0x00, 0x64, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x67, 0x00, 0x3D,
                        0x00, 0x22, 0x00, 0x75, 0x00, 0x6E, 0x00, 0x69, 0x00, 0x63, 0x00, 0x6F,
                        0x00, 0x64, 0x00, 0x65, 0x00, 0x46, 0x00, 0x46, 0x00, 0x46, 0x00, 0x45,
                        0x00, 0x22, 0x00, 0x3F, 0x00, 0x3E, 0x00, 0x0A, 0x00, 0x3C, 0x01, 0x61, 
                        0x00, 0x3E, 0x00, 0x0A, 0x00, 0x3C, 0x00, 0x2F, 0x01, 0x61, 0x00, 0x3E,
    },
        new byte[] { // UTF8
                        0xEF, 0xBB, 0xBF, 0x3C, 0x3F, 0x78, 0x6D, 0x6C, 0x20, 0x76, 0x65, 0x72,
                        0x73, 0x69, 0x6F, 0x6E, 0x3D, 0x22, 0x31, 0x2E, 0x30, 0x22, 0x20, 0x65,
                        0x6E, 0x63, 0x6F, 0x64, 0x69, 0x6E, 0x67, 0x3D, 0x22, 0x75, 0x74, 0x66, 
                        0x2D, 0x38, 0x22, 0x3F, 0x3E, 0x0A, 0x3C, 0xC5, 0xA1, 0x3E, 0x0A, 0x3C, 
                        0x2F, 0xC5, 0xA1, 0x3E
                    },
        new byte[] { // UTF8 - no BOM
                                          0x3C, 0x3F, 0x78, 0x6D, 0x6C, 0x20, 0x76, 0x65, 0x72,
                        0x73, 0x69, 0x6F, 0x6E, 0x3D, 0x22, 0x31, 0x2E, 0x30, 0x22, 0x20, 0x65,
                        0x6E, 0x63, 0x6F, 0x64, 0x69, 0x6E, 0x67, 0x3D, 0x22, 0x75, 0x74, 0x66, 
                        0x2D, 0x38, 0x22, 0x3F, 0x3E, 0x0A, 0x3C, 0xC5, 0xA1, 0x3E, 0x0A, 0x3C, 
                        0x2F, 0xC5, 0xA1, 0x3E
                    },
    };

    static Encoding[] encodings = {
        new UnicodeEncoding(false, true), // unicode - little endian
        new UnicodeEncoding(false, false), // unicode - little endian, NO BOM
        new UnicodeEncoding(true, true), // unicode - big endian
        new UnicodeEncoding(true, false), // unicode - big endian, NO BOM
        new UTF8Encoding(true), // UTF8
        new UTF8Encoding(false), // UTF8 - no BOM
    };

    static bool EqualBytes(byte[] a, byte[] b) 
    {
        if (a.Length != b.Length) return false;

        for (int i = 0; i < a.Length; i++)
            if (a[i] != b[i]) return false;

        return true;
    }

    static String BytesToString(byte[] a) 
    {
        StringBuilder sb = new StringBuilder();

        for (int i = 0; i < a.Length; i++)
            sb.AppendFormat("0x{0:X2}, ", a[i]);

        return sb.ToString();   
    }

    public static void Main() 
    {
        for (int i = 0; i < cases.Length; i++) 
        {
            Encoding e = encodings[i];
            Console.WriteLine("Case " + i + " " + e.ToString());

            byte[] c = cases[i];

            XmlDocument d = new XmlDocument();

            Stream sin = new MemoryStream(c);
            d.Load(sin);

            MemoryStream sout = new MemoryStream();
            StreamWriter sw = new StreamWriter(sout, encodings[i]);
            sw.NewLine = "\n";
            d.Save(sw);

            byte[] r = sout.ToArray();

            if (!EqualBytes(c, r)) 
            {
                Console.WriteLine("Expected: " + BytesToString(c));
                Console.WriteLine("Actual:   " + BytesToString(r));
                Console.WriteLine("FAILED");
                Environment.Exit(1);
            }
        }
        Console.WriteLine("SUCCEEDED");
        Environment.Exit(0);
    }
}
